#include <buola/scene.h>
#include <buola/scene/geodes/cpointcloud.h>
#include <buola/app/ceventloop.h>
#include <buola/image/io.h>
#include <buola/image/cgc.h>
#include <buola/app/ccmdline.h>
#include <buola/app/capp.h>
#include <buola/scene/cscene.h>
#include <buola/scene/cimagerenderer.h>
#include <buola/scene/csceneview.h>
#include <buola/scene/cperspectivecamera.h>
#include <buola/scene/transform/crttransform.h>
#include <buola/gui/ctoolkit.h>
#include <buola/scene/geodes/ccube.h>
#include <buola/scene/controllers/ccameracontroller.h>

using namespace buola;

int main(int pNArg,char **pArgs)
{
    buola_init(pNArg,pArgs);

    try
    {
        CApp lApp;
        
        gui::get_toolkit()->GetOpenGLGC()->MakeCurrent();

        //create the scene
        scene::PScene lScene=new scene::CScene;
        
        io::CURI lURI=io::get_home()/"tabletop.pcd";
        if(cmd_line().ArgCount())
            lURI=io::uri(cmd_line().Arg(0));

        scene::PCube lCube=new scene::CCube;
        scene::PRTTransform lTransform=new scene::CRTTransform(mat::CQuat_d(),{0,0,5});
        lCube->AttachTo(lTransform);
        lScene->World()->AddChild(lTransform);

        scene::PPointCloud lCloud=new scene::CPointCloud(cvi::load_cloud(lURI));
        lScene->World()->AddObject(lCloud);

        scene::PPerspectiveCamera lCamera=new scene::CPerspectiveCamera;
        lCamera->SetFOV(2*atan2(240.0,525.0));
        lCamera->SetClipping(0.1,50.0);
        lCamera->LookAt({0,0,1},{0,0,0},{0,-1,0});

        scene::CImageRenderer lRenderer;
        lRenderer.SetCamera(lCamera);
        lRenderer.AddScene(lScene);
        

        img::CImage_rgb8 lImage({640,640});
        
        lRenderer.GetImage(lImage);

        img::save(lImage,io::file("scene.ppm"));
        
        scene::PSceneView lView=new scene::CSceneView;
        lView->SetCamera(lCamera);
        lView->AddScene(lScene);
        lView->AddController(new scene::CCameraController(lCamera));
        lView->Map(CSize_d(800,600));
        
        lApp.Run();
    }
    catch(std::exception &pE)
    {
        msg_info() << "caught exception " << pE.what() << "\n";
    }

    return buola_finish();
}
